package logic.configuration;


import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;

/*
 * W Sax nie ma możliwości nawigacji w przód tyl,
 * pamietanie relacji parent child należy implementować samodzielnie z wykorzystniem np. stosu
 * preferowane są parsery bezstanowe
 */
public class ConfigXMLDefaultSAXHandler extends DefaultHandler {
	
	static String ID = "id";
	static String NAME = "name";
	static String HANDLER_CLASS = "handler-class";
	static String KEY = "key";
	static String ICON = "icon";
	static String HINT = "hint";
	static String COMMAND_SPEC = "command-spec";
	static String MENU = "menu";
	static String TOOLBAR = "toolbar";
	static String COMMAND = "command";
	static String FILE_MENU = "File";
	static String EDIT_MENU = "Edit";
	static String EMPTY = "";
	
	Logger logger = Logger.getLogger(XMLConfigurationLoader.class.getName());
	
	List<CommandSpec> commandSpecs = new LinkedList<CommandSpec>();
	
	MenuCommands menuCommands = new MenuCommands();
	
	List<String> toolbarCommands = new LinkedList<String>();
	
	Configuration configuration;
	
	//enum moze bylby lepszym rozwiazaniem
	String currentEl = EMPTY;		
	String currentElementValue = EMPTY;
	
	boolean isToolbar = false;
	boolean isMenu = false;
	
	String id;
	String name;
	String handlerClass;
	String key;
	String icon;
	String hint;
	
	String menuName;
	
	ConfigXMLDefaultSAXHandler() { }
	
	
	@Override
	public void startElement(String uri, String localName, String qName, 
			Attributes attributes) {

		currentElementValue = EMPTY;
		
		//check data sic!
		if (qName.equalsIgnoreCase(ID)) {
			currentEl = ID;
		} else if (qName.equalsIgnoreCase(NAME)) {
			currentEl = NAME;
		} else if (qName.equalsIgnoreCase(HANDLER_CLASS)) {
			currentEl = HANDLER_CLASS;
		} else if (qName.equalsIgnoreCase(KEY)) {
			currentEl = KEY;
		} else if (qName.equalsIgnoreCase(ICON)) {
			currentEl = ICON;
		} else if (qName.equalsIgnoreCase(HINT)) {
			currentEl = HINT;
		} else if (qName.equalsIgnoreCase(COMMAND_SPEC)) {
			currentEl = COMMAND_SPEC;
		} else if (qName.equalsIgnoreCase(MENU)) {
			currentEl = MENU;
			isMenu = true;
			menuName = attributes.getValue("name");
		} else if (qName.equalsIgnoreCase(TOOLBAR)) {
			currentEl = TOOLBAR;
			isToolbar = true;
		} else {
			currentEl = EMPTY;
		}
	}
	
	@Override
	public void endElement(String uri, String localName, String qName) {
		if (qName.equals(ID)) {
			id = currentElementValue;
		} else if (qName.equals(NAME)) {
			name = currentElementValue;
		
		} else if (qName.equals(HANDLER_CLASS)) {
			handlerClass = currentElementValue;
		
		} else if (qName.equals(KEY)) {
			key = currentElementValue;
		
		} else if (qName.equals(ICON)) {
			icon = currentElementValue;
		
		} else if (qName.equals(HINT)) {
			logger.info("HINT:" + currentElementValue);
			hint = currentElementValue;
		
		} else if (qName.equals(COMMAND)) {
			
			if (isMenu) {
				if (menuName.equalsIgnoreCase(FILE_MENU)) {
					menuCommands.addFileMenuCommand(currentElementValue);
					
				} else if (menuName.equalsIgnoreCase(EDIT_MENU)) {
					menuCommands.addEditMenuCommand(currentElementValue);
					
				}
				
			} else if (isToolbar) {
				toolbarCommands.add(currentElementValue);
			}
		} else if (qName.equalsIgnoreCase(TOOLBAR)) {
			isToolbar = false;
		} else if (qName.equalsIgnoreCase(MENU)) {
			isMenu = false;
		}
		
		currentElementValue = EMPTY;
		currentEl = EMPTY;
		
		if (qName.equalsIgnoreCase(COMMAND_SPEC)) {
			commandSpecs.add(new CommandSpec(
					id, name, handlerClass, key, icon, hint));
		}

	}
	
	//metoda characters może być wywołana niekokreśloną liczbę razy w ramach jednego elementu
	//wyifowanie, by nie zapamietywal znakow za kazdym razem a tylko z odpoweidnich elementow
	@Override
	public void characters(char[] ch, int start, int length) {
		
		//tutaj moze się przydać currentEl to sprawdzania, by nie czytac zawartosci niepotrzebnych węzłów
		currentElementValue += new String(ch, start, length);
		
	}
	
	@Override
	public void endDocument() {
		//zbudowanie calego obiektu Configuration
		
		configuration = new Configuration(commandSpecs, toolbarCommands, menuCommands);
		
	}
	
	public Configuration getConfiguration() {
		return configuration;
	}
	
	//_________FOR TESTS_______________________
	//typ zmieniony dla testów
	public List<CommandSpec> getCommandSpecs() {
		return commandSpecs;
	}


	/**
	 * @return the menuCommands
	 */
	public MenuCommands getMenuCommands() {
		return menuCommands;
	}


	/**
	 * @return the toolbarCommands
	 */
	public List<String> getToolbarCommands() {
		return toolbarCommands;
	}
	
}